package com.telenav.serverproxy;

import java.util.Vector;

import com.telenav.comm.Comm;
import com.telenav.comm.Host;
import com.telenav.comm.ICommCallback;

public abstract class AbstractServerProxy
{
    protected ServerProxyCommCallback serverProxyCommCallback;
    
    protected Host host;

    protected Comm comm;

    protected IServerProxyListener listener;

    protected String actionId;

    protected int status;

    protected String errorMessage;
    
    private Object jobMutex = new Object();

    private Vector jobPool = new Vector();
    
    public AbstractServerProxy(Host host, Comm comm, IServerProxyListener serverProxyListener)
    {
        this.host = host;
        this.comm = comm;
        this.listener = serverProxyListener;
        
        serverProxyCommCallback = new ServerProxyCommCallback();
    }
    
    public void setHost(Host host)
    {
        this.host = host;
    }
    
    public void setComm(Comm comm)
    {
        this.comm = comm;
    }

    public int cancel()
    {
        synchronized (jobMutex)
        {
            for (int i = 0; i < jobPool.size(); i++)
            {
                this.comm.cancelJob((String)jobPool.elementAt(i));
            }
            jobPool.removeAllElements();
        }

        return IServerProxyConstants.SUCCESS;
    }

    public void reset()
    {
        this.cancel();

        this.status = -1;
        this.errorMessage = "";
    }

    public String getErrorMsg()
    {
        return this.errorMessage;
    }

    public void setErrorMsg(String errorMessage)
    {
        this.errorMessage = errorMessage;
    }
    
    public int getStatus()
    {
        return this.status;
    }
    
    public String getRequestAction()
    {
        return this.actionId;
    }

    protected Host getHostByAction(String action)
    {
        Host requestHost = null;
        if (action != null && action.length() > 0)
        {
            requestHost = this.comm.getHostProvider().createHost(action);
            host = requestHost;
        }

        if(requestHost == null)
            requestHost = this.host;
        
        return requestHost;
    }
    
    protected String sendData(byte[] request, String action)
    {
        return this.sendData(request, action, (byte) 0, 60 * 1000);
    }
    
    protected String sendData(byte[] request, String action, byte retryTimes, int timeout)
    {
        this.actionId = action;
        this.errorMessage = null;
        this.status = -1;
        
        Host requestHost = getHostByAction(action);

        String jobId = this.comm.sendData(this.actionId, requestHost, request, retryTimes, timeout, serverProxyCommCallback);

        addJobToList(jobId);

        return jobId;
    }

    protected abstract void handleResponse(byte[] response);
    
    protected void addJobToList(String jobId)
    {
        synchronized (jobMutex)
        {
            this.jobPool.addElement(jobId);
        }
    }

    protected void removeJobFromList(String jobId)
    {
        synchronized (jobMutex)
        {
            this.jobPool.removeElement(jobId);
        }
    }
    
    public class ServerProxyCommCallback implements ICommCallback
    {
        public void handleChild(ICommCallback.CommResponse response)
        {
            handleResponse(response.responseData);
            response.responseData = null;
        }

        public boolean isAllowNetworkRequest(ICommCallback.CommResponse response)
        {
            return true;
        }

        public void networkError(ICommCallback.CommResponse response)
        {
            removeJobFromList(response.jobId);

            if(response.errorMessage != null &&
                   response.errorMessage.length() > 0 &&
                      response.exception == null)
            {
                AbstractServerProxy.this.errorMessage = response.errorMessage;
            }
            
            AbstractServerProxy.this.status = IServerProxyConstants.FAILED;

            if (AbstractServerProxy.this.listener != null)
            {
                AbstractServerProxy.this.listener.networkError(AbstractServerProxy.this, response.status, response.jobId);
            }
        }

        public void networkFinished(ICommCallback.CommResponse response)
        {
            removeJobFromList(response.jobId);

            if (AbstractServerProxy.this.listener != null)
            {
            	AbstractServerProxy.this.listener.transactionFinished(AbstractServerProxy.this, response.jobId);
            }
        }
    }
}
